package com.gusto.engine.recommend.prediction.base;

import java.util.List;

import com.gusto.engine.colfil.Distance;
import com.gusto.engine.colfil.Prediction;
import com.gusto.engine.recommend.PredictionService;
import com.gusto.engine.recommend.prediction.params.HybridParams;

/**
 * <p>Basic implementation for Hybrid algorithms.<p>
 * 
 * @see BaseCollaborativeImpl
 * @see BaseSemanticImpl
 * @see BaseHybridImpl
 * 
 * @author amokrane.belloui@gmail.com
 *
 */
public abstract class BaseHybridImpl extends BaseImpl implements PredictionService {
	
	protected HybridParams params = new HybridParams();
	public void setParams(HybridParams params) {
		this.params = params;
	}
	public HybridParams getParams() {
		return params;
	}
	
	protected long nbHybrid;
	protected long nbCollaborative;
	protected long nbSemantic;
	
	public Prediction predict(long userId, long itemId, boolean includePrediction) throws Exception {
		long start = System.currentTimeMillis();
		
		Double val = null; 
		val = _predict(userId, itemId, includePrediction);
		
		String message = "Hybrid Combination (hyb:" + nbHybrid + ", col:" + nbCollaborative + ", sem:" + nbSemantic + ")";
		logPrediction(0, 0, 0, (System.currentTimeMillis() - start), message);
		return returnPrediction(userId, itemId, val);
	}
	
	
	public Double _predict(long userId, long itemId, boolean includePrediction) throws Exception {
		// Collaborative Neighborhood
		List<Distance> usersCol = collaborativeNeighborhoodDelegate.getNearUsers(userId, params.getColUserFormula(), params.getColUserMinShared(), params.getColUserMaxNeighbors(), params.getColUserMinSimilarity());
		List<Distance> itemsCol = collaborativeNeighborhoodDelegate.getNearItems(itemId, params.getColItemFormula(), params.getColItemMinShared(), params.getColItemMaxNeighbors(), params.getColItemMinSimilarity());
		
		// Semantic Neighborhood
		List<Distance> usersSem = semanticNeighborhoodDelegate.getNearUsers(userId, params.getSemUserMaxNeighbors(), params.getSemUserMinSimilarity());
		List<Distance> itemsSem = semanticNeighborhoodDelegate.getNearItems(itemId, params.getSemItemMaxNeighbors(), params.getSemItemMinSimilarity());
		
		Double val = doPrediction(userId, itemId, usersCol, itemsCol, usersSem, itemsSem);
		
		return val;
	}
	
	protected abstract Double doPrediction(long userId, long itemId, 
			List<Distance> userNeighborhoodCol,
			List<Distance> itemNeighborhoodCol,
			List<Distance> userNeighborhoodSem,
			List<Distance> itemNeighborhoodSem);
	
	
}
